--- title: "15-MySQL 编程基础" created: 2026-01-08 tags: - 项目筑基 --- # MySQL 编程基础 ## **第十章:MySQL 编程基础** > 💡 MySQL 支持存储过程、函数、触发器等编程功能,本章介绍MySQL编程基础 ### **10.1 MySQL 编程概述** #### **10.1.1 MySQL vs SQL Server 编程对比** | **特性** | **SQL Server (T-SQL)** | **MySQL** | | --- | --- | --- | | 编程语言 | T-SQL | MySQL存储程序语言 | | 变量声明 | `DECLARE @var INT` | `DECLARE var INT` | | 变量赋值 | `SET @var = 1` | `SET var = 1` | | 输出语句 | `PRINT '内容'` | `SELECT '内容'` | | IF语句 | `IF...ELSE` | `IF...THEN...END IF` | | 循环 | `WHILE...BEGIN...END` | `WHILE...DO...END WHILE` | ### **10.2 变量与数据类型** #### **10.2.1 用户变量** ```sql -- 用户变量(以@开头,会话级别) SET @name = '张三'; SET @age = 20; -- 查询中赋值 SELECT @total := COUNT(*) FROM 学生; -- 使用用户变量 SELECT @name, @age, @total; ``` #### **10.2.2 局部变量** ```sql -- 局部变量只能在BEGIN...END中使用 -- 必须先声明后使用 DELIMITER // CREATE PROCEDURE test_var() BEGIN -- 声明局部变量 DECLARE v_name VARCHAR(20); DECLARE v_age INT DEFAULT 0; DECLARE v_count INT; -- 赋值 SET v_name = '李四'; SET v_age = 25; SELECT COUNT(*) INTO v_count FROM 学生; -- 输出 SELECT v_name, v_age, v_count; END // DELIMITER ; ``` ### **10.3 常用函数** #### **10.3.1 字符串函数** ```sql -- ASCII 和 CHAR SELECT ASCII('A'); -- 65 SELECT ASCII('AB'); -- 65(只返回第一个字符的ASCII码) SELECT CHAR(65); -- 'A' -- 大小写转换 SELECT LOWER('HELLO WORLD'); -- 'hello world' SELECT UPPER('hello world'); -- 'HELLO WORLD' -- 去空格 SELECT LTRIM(' hello '); -- 'hello ' SELECT RTRIM(' hello '); -- ' hello' SELECT TRIM(' hello '); -- 'hello' -- 截取字符串 SELECT LEFT('江西服装学院', 2); -- '江西' SELECT RIGHT('江西服装学院', 2); -- '学院' SELECT SUBSTRING('江西服装学院', 3, 2); -- '服装'(从第3个字符开始,取2个) -- 字符串长度 SELECT LENGTH('hello'); -- 5(字节数) SELECT CHAR_LENGTH('你好'); -- 2(字符数) SELECT LENGTH('你好'); -- 6(UTF-8编码,每个汉字3字节) -- 字符串查找 SELECT LOCATE('world', 'hello world'); -- 7(返回位置,从1开始) SELECT INSTR('hello world', 'world'); -- 7 SELECT POSITION('world' IN 'hello world'); -- 7 -- 字符串替换 SELECT REPLACE('hello world', 'world', 'MySQL'); -- 'hello MySQL' -- 字符串连接 SELECT CONCAT('hello', ' ', 'world'); -- 'hello world' SELECT CONCAT_WS('-', '2024', '01', '15'); -- '2024-01-15' -- 重复字符串 SELECT REPEAT('ABC', 3); -- 'ABCABCABC' -- 反转字符串 SELECT REVERSE('hello'); -- 'olleh' -- 格式化输出 SELECT FORMAT(12345.6789, 2); -- '12,345.68' ``` #### **10.3.2 数学函数** ```sql -- 三角函数 SELECT SIN(PI()/2), COS(0), TAN(PI()/4); -- 取整函数 SELECT CEIL(1.1); -- 2(向上取整) SELECT CEILING(1.1); -- 2 SELECT FLOOR(1.9); -- 1(向下取整) SELECT ROUND(2.567, 2); -- 2.57(四舍五入,保留2位小数) SELECT TRUNCATE(2.567, 2); -- 2.56(截断,保留2位小数) -- 绝对值 SELECT ABS(-125); -- 125 -- 符号函数 SELECT SIGN(5); -- 1(正数) SELECT SIGN(-5); -- -1(负数) SELECT SIGN(0); -- 0 -- 幂运算 SELECT POWER(2, 3); -- 8 SELECT POW(2, 3); -- 8 SELECT SQRT(16); -- 4 -- 随机数 SELECT RAND(); -- 0到1之间的随机数 SELECT FLOOR(RAND() * 100); -- 0到99的随机整数 -- 取模 SELECT MOD(10, 3); -- 1 SELECT 10 % 3; -- 1 ``` #### **10.3.3 日期时间函数** ```sql -- 获取当前日期时间 SELECT NOW(); -- '2024-01-15 10:30:00' SELECT CURRENT_TIMESTAMP(); -- 同NOW() SELECT CURDATE(); -- '2024-01-15' SELECT CURRENT_DATE(); -- 同CURDATE() SELECT CURTIME(); -- '10:30:00' SELECT CURRENT_TIME(); -- 同CURTIME() -- 日期时间提取 SELECT YEAR('2024-01-15'); -- 2024 SELECT MONTH('2024-01-15'); -- 1 SELECT DAY('2024-01-15'); -- 15 SELECT HOUR('10:30:45'); -- 10 SELECT MINUTE('10:30:45'); -- 30 SELECT SECOND('10:30:45'); -- 45 SELECT DAYOFWEEK('2024-01-15'); -- 2(1=周日,2=周一...) SELECT DAYNAME('2024-01-15'); -- 'Monday' -- 日期计算 SELECT DATE_ADD('2024-01-15', INTERVAL 10 DAY); -- '2024-01-25' SELECT DATE_ADD('2024-01-15', INTERVAL 1 MONTH); -- '2024-02-15' SELECT DATE_SUB('2024-01-15', INTERVAL 1 YEAR); -- '2023-01-15' SELECT DATEDIFF('2024-12-31', '2024-01-01'); -- 365(相差天数) -- 日期格式化 SELECT DATE_FORMAT('2024-01-15', '%Y年%m月%d日'); -- '2024年01月15日' SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s'); -- '2024-01-15 10:30:00' -- 字符串转日期 SELECT STR_TO_DATE('15/01/2024', '%d/%m/%Y'); -- '2024-01-15' ``` **日期格式化符号:** | **符号** | **说明** | **示例** | | --- | --- | --- | | `%Y` | 四位年份 | 2024 | | `%y` | 两位年份 | 24 | | `%m` | 月份(01-12) | 01 | | `%d` | 日期(01-31) | 15 | | `%H` | 小时(00-23) | 14 | | `%i` | 分钟(00-59) | 30 | | `%s` | 秒(00-59) | 45 | | `%W` | 星期名称 | Monday | | `%M` | 月份名称 | January | #### **10.3.4 类型转换函数** ```sql -- CAST函数 SELECT CAST('123' AS SIGNED); -- 123(转为整数) SELECT CAST(123.456 AS CHAR); -- '123.456'(转为字符串) SELECT CAST('2024-01-15' AS DATE); -- 2024-01-15 SELECT CAST(NOW() AS DATE); -- 只保留日期部分 -- CONVERT函数 SELECT CONVERT('123', SIGNED); -- 123 SELECT CONVERT(NOW(), DATE); -- 2024-01-15 -- 字符集转换 SELECT CONVERT('你好' USING utf8mb4); ``` #### **10.3.5 流程控制函数** ```sql -- IF函数 SELECT IF(1 > 0, '真', '假'); -- '真' SELECT IF(score >= 60, '及格', '不及格') FROM 成绩; -- IFNULL函数(空值替换) SELECT IFNULL(NULL, '默认值'); -- '默认值' SELECT IFNULL(成绩, 0) FROM 选课成绩; -- NULLIF函数 SELECT NULLIF(1, 1); -- NULL(两个值相等返回NULL) SELECT NULLIF(1, 2); -- 1(不相等返回第一个值) -- COALESCE函数(返回第一个非NULL值) SELECT COALESCE(NULL, NULL, '第三个'); -- '第三个' -- CASE WHEN THEN SELECT 姓名, CASE WHEN 成绩 >= 90 THEN '优秀' WHEN 成绩 >= 80 THEN '良好' WHEN 成绩 >= 60 THEN '及格' ELSE '不及格' END AS 等级 FROM 学生成绩; -- CASE 简单形式 SELECT 姓名, CASE 性别 WHEN 'M' THEN '男' WHEN 'F' THEN '女' ELSE '未知' END AS 性别 FROM 学生; ``` ### **10.4 流程控制语句** #### **10.4.1 IF 语句** ```sql -- IF 语句(只能在存储过程/函数中使用) DELIMITER // CREATE PROCEDURE check_score(IN p_score INT) BEGIN IF p_score >= 90 THEN SELECT '优秀'; ELSEIF p_score >= 80 THEN SELECT '良好'; ELSEIF p_score >= 60 THEN SELECT '及格'; ELSE SELECT '不及格'; END IF; END // DELIMITER ; -- 调用 CALL check_score(85); ``` #### **10.4.2 CASE 语句** ```sql DELIMITER // CREATE PROCEDURE grade_level(IN p_grade INT) BEGIN CASE WHEN p_grade >= 90 THEN SELECT '优秀'; WHEN p_grade >= 80 THEN SELECT '良好'; WHEN p_grade >= 60 THEN SELECT '及格'; ELSE SELECT '不及格'; END CASE; END // DELIMITER ; ``` #### **10.4.3 WHILE 循环** ```sql DELIMITER // CREATE PROCEDURE sum_1_to_n(IN n INT) BEGIN DECLARE i INT DEFAULT 1; DECLARE total INT DEFAULT 0; WHILE i <= n DO SET total = total + i; SET i = i + 1; END WHILE; SELECT total AS 总和; END // DELIMITER ; -- 调用 CALL sum_1_to_n(100); -- 结果:5050 ``` #### **10.4.4 LOOP 循环** ```sql DELIMITER // CREATE PROCEDURE sum_loop(IN n INT) BEGIN DECLARE i INT DEFAULT 1; DECLARE total INT DEFAULT 0; loop_label: LOOP IF i > n THEN LEAVE loop_label; -- 跳出循环 END IF; SET total = total + i; SET i = i + 1; END LOOP loop_label; SELECT total AS 总和; END // DELIMITER ; ``` #### **10.4.5 REPEAT 循环** ```sql DELIMITER // CREATE PROCEDURE sum_repeat(IN n INT) BEGIN DECLARE i INT DEFAULT 1; DECLARE total INT DEFAULT 0; REPEAT SET total = total + i; SET i = i + 1; UNTIL i > n END REPEAT; SELECT total AS 总和; END // DELIMITER ; ``` #### **10.4.6 循环控制** ```sql -- LEAVE:跳出循环(类似break) -- ITERATE:跳过本次循环(类似continue) DELIMITER // CREATE PROCEDURE loop_control_demo() BEGIN DECLARE i INT DEFAULT 0; my_loop: LOOP SET i = i + 1; -- 跳过偶数 IF i % 2 = 0 THEN ITERATE my_loop; END IF; -- 大于10跳出 IF i > 10 THEN LEAVE my_loop; END IF; SELECT i; END LOOP my_loop; END // DELIMITER ; ``` ### **10.5 实战示例** #### **10.5.1 计算年龄** ```sql DELIMITER // CREATE FUNCTION calc_age(birthday DATE) RETURNS INT DETERMINISTIC BEGIN DECLARE age INT; SET age = TIMESTAMPDIFF(YEAR, birthday, CURDATE()); -- 如果今年生日还没到,年龄减1 IF DATE_FORMAT(CURDATE(), '%m%d') < DATE_FORMAT(birthday, '%m%d') THEN SET age = age - 1; END IF; RETURN age; END // DELIMITER ; -- 使用 SELECT calc_age('2000-06-15'); SELECT 姓名, 出生日期, calc_age(出生日期) AS 年龄 FROM 学生; ``` #### **10.5.2 复利计算** ```sql DELIMITER // CREATE PROCEDURE compound_interest( IN principal DECIMAL(10,2), -- 本金 IN rate DECIMAL(5,4), -- 年利率 IN target DECIMAL(10,2), -- 目标金额 OUT years INT, -- 需要年数 OUT final_amount DECIMAL(10,2) -- 最终金额 ) BEGIN DECLARE amount DECIMAL(10,2); SET amount = principal; SET years = 0; WHILE amount < target DO SET amount = amount * (1 + rate); SET years = years + 1; END WHILE; SET final_amount = amount; END // DELIMITER ; -- 调用:本金10000,年利率5%,目标20000 CALL compound_interest(10000, 0.05, 20000, @years, @final); SELECT @years AS 需要年数, @final AS 最终金额; ``` #### **10.5.3 成绩等级转换** ```sql DELIMITER // CREATE PROCEDURE convert_scores() BEGIN SELECT 学号, 姓名, 数学, CASE WHEN 数学 >= 85 THEN '优秀' WHEN 数学 >= 60 THEN '及格' ELSE '不及格' END AS 数学等级, 英语, CASE WHEN 英语 >= 85 THEN '优秀' WHEN 英语 >= 60 THEN '及格' ELSE '不及格' END AS 英语等级, 语文, CASE WHEN 语文 >= 85 THEN '优秀' WHEN 语文 >= 60 THEN '及格' ELSE '不及格' END AS 语文等级 FROM 成绩表; END // DELIMITER ; CALL convert_scores(); ``` --- ⬅️ [[14-视图|视图]] 🏠 [[00-数据库|00-数据库]] ➡️ [[16-存储过程与函数|存储过程与函数]]